﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Publicuse.Util
{
    /// <summary>
    /// FTP工具类
    /// </summary>
    public class FtpUtil
    {
        public static string ftpServerIP { get; set; }//服务器ip  
        public static string ftpUserID { get; set; }//用户名  
        public static string ftpPassword { get; set; }//密码  

        /// <summary>  
        /// 上传文件  
        /// </summary>  
        /// <param name="localFile">要上传到FTP服务器的本地文件</param>  
        /// <param name="ftpPath">FTP地址</param>  
        public static void UpLoadFTP(string localFile, string ftpPath, out string msg)
        {
            msg = null;
            FtpWebRequest reqFTP = null;
            FileStream fs = null;
            try
            {
                if (!File.Exists(localFile))
                {
                    return;
                }
                FileInfo fileInf = new FileInfo(localFile);

                reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpPath));// 根据uri创建FtpWebRequest对象  
                reqFTP.Timeout = 6000 * 20;//设定超时  
                reqFTP.ReadWriteTimeout = 6000 * 20;
                reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);// ftp用户名和密码  
                reqFTP.UsePassive = true;
                reqFTP.EnableSsl = false; // 是否使用ssl 默认不用
                reqFTP.KeepAlive = true;// 默认为true，连接不会被关闭 // 在一个命令之后被执行  
                reqFTP.Method = WebRequestMethods.Ftp.UploadFile;// 指定执行什么命令  
                reqFTP.ReadWriteTimeout = 6000 * 20;//读写超时时间 
                reqFTP.UseBinary = true;// 指定数据传输类型  
                reqFTP.ContentLength = fileInf.Length;// 上传文件时通知服务器文件的大小  
                int buffLength = 2048;// 缓冲大小设置为2kb  
                byte[] buff = new byte[buffLength];
                int contentLen;

                fs = fileInf.OpenRead();
                // 把上传的文件写入流  
                using (Stream strm = reqFTP.GetRequestStream())
                {
                    contentLen = fs.Read(buff, 0, buffLength);// 每次读文件流的2kb  
                    while (contentLen != 0)// 流内容没有结束  
                    {
                        // 把内容从file stream 写入 upload stream  
                        strm.Write(buff, 0, contentLen);
                        contentLen = fs.Read(buff, 0, buffLength);
                    }
                }
            }
            catch (Exception ex)
            {
                if (fs != null)
                {
                    fs.Flush();
                    fs.Close();
                    fs.Dispose();
                }
                reqFTP.Abort();
                LogUtil.GetInstance.WriteLogOld($"上传FTP数据异常", ex.Message + "|" + ex.StackTrace, true);
                msg = ex.Message;
            }
            finally
            {
                fs.Flush();
                fs.Close();
                fs.Dispose();
                reqFTP.Abort();
            }
        }

        /// <summary>  
        /// 上传整个目录  
        /// </summary>  
        /// <param name="localDir">要上传的目录的上一级目录</param>  
        /// <param name="ftpPath">FTP路径</param>  
        /// <param name="dirName">要上传的目录名</param>  
        /// <param name="ftpUser">FTP用户名（匿名为空）</param>  
        /// <param name="ftpPassword">FTP登录密码（匿名为空）</param>  
        public static void UploadDirectory(string localDir, string dirName, string today, out string msg, bool isyctftp = false)
        {
            msg = null;
            try
            {
                if (isyctftp)
                {
                    UpLoadFTP(localDir, dirName, out msg);
                }
                else
                {
                    string dir = localDir + "/" + today;
                    if (!CheckDirectoryExist(ftpServerIP, dirName + "/" + today, out msg))
                    {
                        if (msg.Contains("未登录"))
                        {
                            msg = "登录失败：IP、用户名或密码错误";
                        }
                        else
                        {
                            MakeDir(ftpServerIP, dirName + "/" + today);//不存在，则创建此文件夹  
                            List<List<string>> infos = GetDirDetails(dir); //获取当前目录下的所有文件和文件夹  
                            for (int i = 0; i < infos[0].Count; i++)
                            {
                                var iszip = infos[0][i].Split('.')[1].ToString() == "zip";
                                //if (!iszip)
                                //{
                                var file = dir + "/" + infos[0][i];
                                var uploadfile = ftpServerIP + dirName + "/" + today + @"/" + infos[0][i];
                                UpLoadFTP(file, uploadfile, out msg);
                                //}
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                msg = ex.Message + "|" + ex.StackTrace;
            }
        }


        /// <summary>  
        /// 判断ftp服务器上该目录是否存在  
        /// </summary>  
        /// <param name="ftpPath">FTP路径目录</param>  
        /// <param name="dirName">目录上的文件夹名称</param>  
        /// <returns></returns>  
        private static bool CheckDirectoryExist(string ftpPath, string dirName, out string msg)
        {
            msg = null;
            bool result = true;
            FtpWebRequest request = null;
            try
            {
                //实例化FTP连接
                request = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpPath + dirName));
                request.Credentials = new NetworkCredential(ftpUserID, ftpPassword);// ftp用户名和密码  
                //指定FTP操作类型为创建目录
                //request.Method = WebRequestMethods.Ftp.ListDirectoryDetails; //SFTP模式判断文件夹是否存在
                request.Method = WebRequestMethods.Ftp.ListDirectory;//FTP模式判断文件夹是否存在
                request.UseBinary = true;
                //获取FTP服务器的响应
                FtpWebResponse response = request.GetResponse() as FtpWebResponse;
                response.Close();
                request.Abort();
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                result = false;
                request.Abort();
            }
            return result;
        }

        /// <summary>  
        /// 创建文件夹    
        /// </summary>    
        /// <param name="ftpPath">FTP路径</param>    
        /// <param name="dirName">创建文件夹名称</param>    
        public static void MakeDir(string ftpPath, string dirName)
        {

            FtpWebRequest reqFTP;
            string newpath = string.Empty;
            var fpaths = dirName.Split('/');
            try
            {
                var i = 0;
                foreach (var fp in fpaths)
                {
                    if (i == 0)
                        newpath = fp;
                    else
                        newpath = dirName;

                    reqFTP = (FtpWebRequest)FtpWebRequest.Create(ftpPath + newpath);
                    reqFTP.UsePassive = false;
                    reqFTP.Method = WebRequestMethods.Ftp.MakeDirectory;
                    reqFTP.UseBinary = true;
                    reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
                    FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
                    Stream ftpStream = response.GetResponseStream();
                    ftpStream.Close();
                    response.Close();
                    reqFTP.Abort();
                    i++;
                }

            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("550"))
                {
                    newpath = dirName;
                    reqFTP = (FtpWebRequest)FtpWebRequest.Create(ftpPath + newpath);
                    reqFTP.UsePassive = true;
                    reqFTP.Method = WebRequestMethods.Ftp.MakeDirectory;
                    reqFTP.UseBinary = true;
                    reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
                    FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
                    Stream ftpStream = response.GetResponseStream();
                    ftpStream.Close();
                    response.Close();
                    reqFTP.Abort();
                }
            }

        }

        /// <summary>  
        /// 获取目录下的详细信息  
        /// </summary>  
        /// <param name="localDir">本机目录</param>  
        /// <returns></returns>  
        private static List<List<string>> GetDirDetails(string localDir)
        {
            List<List<string>> infos = new List<List<string>>();
            try
            {
                infos.Add(Directory.GetFiles(localDir).ToList()); //获取当前目录的文件  

                infos.Add(Directory.GetDirectories(localDir).ToList()); //获取当前目录的目录  

                for (int i = 0; i < infos[0].Count; i++)
                {
                    int index = infos[0][i].LastIndexOf(@"\");
                    infos[0][i] = infos[0][i].Substring(index + 1);
                }
                for (int i = 0; i < infos[1].Count; i++)
                {
                    int index = infos[1][i].LastIndexOf(@"\");
                    infos[1][i] = infos[1][i].Substring(index + 1);
                }
            }
            catch (Exception ex)
            {
                ex.ToString();
            }
            return infos;
        }

        /// <summary>
        /// 获取当前目录下文件夹
        /// </summary>
        /// <returns></returns>
        public static string[] GetFilesDirList(string path)
        {
            try
            {
                StringBuilder result = new StringBuilder();//如果要修改字符串而不创建新的对象，则可以使用 System.Text.StringBuilder 类。
                FtpWebRequest ftp;
                ftp = (FtpWebRequest)FtpWebRequest.Create(new Uri(path));
                ftp.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
                ftp.Method = WebRequestMethods.Ftp.ListDirectoryDetails;//目录
                WebResponse response = ftp.GetResponse();//response为一个ftp的WebResponse
                StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default);//读入responses所创建的数据流
                string line = reader.ReadLine();//输入流中的下一行；如果到达了输入流的末尾，则为空引用
                while (line != null)
                {
                    result.Append(line);//)Append 方法可用来将文本或对象的字符串表示形式添加到由当前 StringBuilder 对象表示的字符串的结尾处。
                    result.Append("\n");
                    line = reader.ReadLine();
                }
                result.Remove(result.ToString().LastIndexOf("\n"), 1);
                reader.Close();
                response.Close();
                return result.ToString().Split('\n');
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 下载FTP文件到本地指定位置
        /// </summary>
        /// <returns></returns>
        public static bool DownFileFormFtp(string url, string filename, out string msg)
        {
            msg = string.Empty;
            try
            {
                //创建文件流
                FileStream fs = null;
                Stream responseStream = null;
                FtpWebRequest ftp;
                ftp = (FtpWebRequest)FtpWebRequest.Create(new Uri(url));
                ftp.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
                ftp.Method = WebRequestMethods.Ftp.DownloadFile;
                WebResponse response = ftp.GetResponse();
                //获取请求的响应流
                responseStream = response.GetResponseStream();
                //判断本地文件是否存在，如果存在，则打开和重写本地文件
                if (File.Exists(filename))
                {
                    fs = File.Open(filename, FileMode.Open, FileAccess.ReadWrite);
                }
                else
                {
                    fs = File.Create(filename);
                }
                if (fs != null)
                {
                    int buffer_count = 65536;
                    byte[] buffer = new byte[buffer_count];
                    int size = 0;
                    while ((size = responseStream.Read(buffer, 0, buffer_count)) > 0)
                    {
                        fs.Write(buffer, 0, size);
                    }
                    fs.Flush();
                    fs.Close();
                    responseStream.Close();
                }
                return true;
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return false;
            }
        }
    }
}
